module XMLModel
  class Document
    def initialize(rootElement)
      @root = rootElement 
    end

    def get_root
      @root
    end

    def set_root(root)
      @root = root
    end

    def to_s
      @root.subtree
    end

    def show_current(cursor)
      puts @root.subtree(0,cursor)
    end

    def show
      puts self
    end
  end

  class Node
    attr_accessor :value

    private_class_method :new

    def initialize(value)
      @value = value
      @children = []
      @parent
    end

    def has_children
      count_children > 0
    end

    def get_value
      @value
    end

    def set_value(value)
      @value = value
    end

    def set_parent(parent)
      @parent = parent
    end

    def get_parent
      @parent
    end

    def add_child(child_node, position = -1)
      child_node.set_parent(self)
      @children.insert(position,child_node)
      self
    end

    def add_after(new_node)
      if @parent.nil?
        nil
      else
        position = @parent.get_child_position(self)
        @parent.add_child(new_node,position+1)
      end
    end

    def add_before(new_node)
      if @parent.nil?
        nil
      else
        position = @parent.get_child_position(self)
        @parent.add_child(new_node,position)
      end
    end

    def get_first_child
      get_child(0)
    end

    def get_last_child
      get_child(-1)
    end

    def get_child(position)
      @children[position]
    end

    def next_sibling
      if @parent.nil?
        nil
      else
        position = @parent.get_child_position(self)
        @parent.get_child(position+1)
      end
    end

    def previous_sibling
      if @parent.nil?
        nil
      else
        position = @parent.get_child_position(self)
        unless(position == 0)
          @parent.get_child(position-1)
        end
      end
    end

    def count_children
      @children.size
    end

    def to_s
      "#{self.class.to_s.upcase}: #{@value}"
    end

    def show
      puts self.to_s
    end

    def subtree(depth = 0, cursor = nil)
      st = ""
      if self == cursor
        st += "~> "
      else
        st += "   "
      end
      if count_children == 0
        st += ("  " * depth) + "<" + @value + "/>\n"
      else
        st += ("  " * depth) + "<" + @value + ">\n"
        @children.each do |child|
          st += "#{child.subtree(depth + 1,cursor)}"
        end
        st += "   "
        st += ("  " * depth) + "</" + @value + ">\n"
      end
    end

    protected
    def get_child_position(child_node)
      @children.index(child_node)
    end

  end

  class Declaration

  end

  class LeafNode < Node
    def add_child(child_node, position = -1)
      raise "ERROR"
    end
  end

  class Comment < LeafNode
    public_class_method :new

    def subtree(depth = 0, cursor)
      st = ""
      if self == cursor
        st += "~> "
      else
        st += "   "
      end
      st += ("  " * depth) + "<!--" + @value + "-->\n"
    end
  end

  class PlainText < LeafNode
    public_class_method :new

    def subtree(depth = 0, cursor)
      st = ""
      if self == cursor
        st += "~> "
      else
        st += "   "
      end
      st += ("  " * depth) + @value + "\n"
    end
  end

  class Element < Node
    attr_accessor :attributes
    public_class_method :new
  end
end